#include "xtime.h"
#include "itime.h"
#include "str.h"
#include <sys/timeb.h>

namespace log4x
{
uint32_t
time::now_sec()
{
    time_t t;
    ::time(&t);

    return (uint32_t)t;
}

uint64_t
time::now_msec()
{
    timeb tb;
    ftime(&tb);

    return (uint64_t)tb.time * 1000 + tb.millitm;
}

uint64_t
time::now_usec()
{
#ifndef _MSC_VER
    struct timeval  tv;
    gettimeofday(&tv, NULL);

    return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
#else
    return now_msec() * 1000;
#endif
}

string
time::now_strf(const char* fmt)
{
    const char* format = fmt;
    if (!format)
    {
        format = "%Y-%m-%d %H:%M:%S";
    }

    time_t t;
    struct tm ltm;
    memset(&ltm, 0, sizeof(tm));
    char buf[128] = {0};

    ::time(&t);

    if (os::time()->localtime(t, ltm) < 0)
    {
        return "";
    }

    if (::strftime(buf, 128, format, &ltm) <= 0)
    {
        return "";
    }

    return string(buf);
}

string
time::now_strfmsec()
{
    uint64_t now  = now_msec();
    time_t   sec  = now / 1000;
    uint64_t msec = now % 1000;

    struct tm ltm;
    memset(&ltm, 0, sizeof(tm));
    char   buf[128] = {0};


    if (os::time()->localtime(sec, ltm) < 0)
    {
        return "";
    }

    if (::strftime(buf, 128, "%Y-%m-%d %H:%M:%S", &ltm) <= 0)
    {
        return "";
    }

    return string(buf) + "." + str::to_str(msec);
}

string
time::strftime(time_t sec, const char* fmt)
{
    struct tm ltm;
    memset(&ltm, 0, sizeof(tm));
    char buffer[128] = {0};

    if (0 == sec)
    {
        ::time(&sec);
    }

    if (os::time()->localtime(sec, ltm) < 0)
    {
        return "";
    }

    const char* format = fmt ? fmt : "%Y-%m-%d %H:%M:%S";
    if (::strftime(buffer, 128, format, &ltm) <= 0)
    {
        return "";
    }
    return string(buffer);
}

string
time::strftime(datetime_s& d, const char* fmt)
{
    if (d.year < 1970
            || d.month < 1
            || d.month > 12
            || d.day < 1
            || d.day > 31)
    {
        return "";
    }

    char buffer[128] = { 0 };
    struct tm tt;
    memset(&tt, 0, sizeof(tm));

    tt.tm_year = d.year - 1900;
    tt.tm_mon  = d.month - 1;
    tt.tm_mday = d.day;
    tt.tm_hour = d.hour;
    tt.tm_min  = d.minute;
    tt.tm_sec  = d.second;

    const char* format = fmt ? fmt : "%Y-%m-%dT%H:%M:%SZ";
    if (::strftime(buffer, 128, format, &tt) <= 0)
    {
        return "";
    }
    return string(buffer);
}

int
time::strptime(const string& s, struct tm& t, const char* fmt)
{
    if (s.empty())
    {
        return -1;
    }

    const char* format = fmt ? fmt : "%Y-%m-%d %H:%M:%S";
    if (NULL == os::time()->strptime(s.c_str(), format, &t))
    {
        return -1;
    }
    return 0;
}

time_t
time::strptime(const string& s, const char* fmt)
{
    struct tm t;
    memset(&t, 0, sizeof(tm));
    if (strptime(s, t, fmt) < 0)
    {
        return -1;
    }
    return mktime(&t);
}

int
time::strptime(const string& s, datetime_s& d, const char* fmt)
{
    if (s.empty())
    {
        return -1;
    }

    const char* format = fmt ? fmt : "%Y-%m-%dT%H:%M:%SZ";
    struct tm tt;
    memset(&tt, 0, sizeof(tm));

    if (!os::time()->strptime(s.c_str(), format, &tt))
    {
        return -1;
    }

    d.year   = tt.tm_year + 1900;
    d.month  = tt.tm_mon + 1;
    d.day    = tt.tm_mday;
    d.hour   = tt.tm_hour;
    d.minute = tt.tm_min;
    d.second = tt.tm_sec;

    return 0;
}
}
